/**
 * PullRefreshListView组件
 *
 * 下拉刷新，无限分页
 *
 * @type {ReactNative|exports|module.exports}
 */
var React = require('react-native');
var fetch = require('./fetch');
//每页显示的数量
var PAGE_SIZE = 10;
//触发下拉请求的边界距离
const OFFSET_Y = 60;
//loading的高度
const LOADING_HEIGHT = 50;
//just do nothing
var noop = () => {};
//当前屏幕的宽度
var SCREEN_WIDTH = require('Dimensions').get('window').width;


var {
  ActivityIndicatorIOS,
  TouchableOpacity,
  InteractionManager,
  PixelRatio,
  StyleSheet,
  ListView,
  View,
  Text,
  Image,
} = React;


/**
 * Usage
 * var {QMPullRefreshListView} = require('qmkit');
 *
 * React.renderClass({
 *  render() {
 *    return (
 *      <PullRefreshListView
 *        url: '/your remote url/',
 *        style={}
 *        renderRow={}
 *      />
 *    );
 *  }
 * });
 */
var PullRefreshListView = React.createClass({
  propTypes: {
    //url必填
    url: React.PropTypes.string.isRequired
  },


  /**
   * 默认属性
   */
  getDefaultProps() {
    return {
      //ajax的url
      url: '',
      //覆盖默认的ListView的样式
      style: null,
      //默认当前的pageSize
      pageSize: PAGE_SIZE,
      //数据回来的callback，
      //便于外界拿到数据去setState
      onDataReceive: noop,
      //自定义头部
      customHeader: null
    }
  },


  /**
   * 初始化当前的状态
   */
  getInitialState() {
    //当前页
    this._page = 0;
    //缓存listview的dataSource
    this._cache = [];

    return {
      /*是不是loading到结尾*/
      isLoadTail: false,

      /*是不是需要刷新，主要是下拉刷新的标识*/
      isRefreshMode: 'refresh',

      /*listview的数据源*/
      dataSource: new ListView.DataSource({
        rowHasChanged(r1, r2) {
          return r1 != r2;
        }
      })
    };
  },


	/**
	 * url变化的话刷新一下
	 */
	componentWillReceiveProps(nextProps) {
		if (this.props.url != nextProps.url) {
			this._init();
		}
	},


  /**
   * 组件将要完成首次加载，获取数据
   */
  componentWillMount() {
    this._init();
  },



  render() {
    var customHeader = this.props.customHeader;
    // 如果没有数据，显示暂无数据
    var isEmpty = this.state.isLoadTail && this._cache.length == 0;
    return (isEmpty && !customHeader) ? this._renderEmptyView(this.props.style) : this._renderListView();
  },


  _renderEmptyView(style) {
    return (
      <View style={[styles.container, style]}>
        <View style={styles.noDataContainer}>
          <Image style={styles.face} source={require('img/empty.png')} />
          <Text style={styles.txt}>暂无数据</Text>
        </View>
        <View style={styles.foot}>
          <TouchableOpacity onPress={this._init} style={styles.button}>
            <Text style={styles.cont}>刷新一下</Text>
          </TouchableOpacity>
        </View>
      </View>
    );
  },


  _renderListView() {
    // 渲染ListView
    return (
      <View style={[styles.container, this.props.style]}>
        <ListView
          ref={(listView) => this._listView = listView}
          initialListSize={20}
          onEndReachedThreshold={100}
          scrollRenderAheadDistance={1000}
          scrollEventThrottle={32}
          keyboardShouldPersistTaps={false}
          onResponderRelease={this._handleResponderRelease}
          onMomentumScrollEnd={this._handleMomentumScrollEnd}
          onScroll={this._handleScroll}
          onEndReached={this._handlePagination}
          dataSource={this.state.dataSource.cloneWithRows(this._cache)}
          renderHeader={this._renderHeader}
          renderRow={this.props.renderRow}
          renderFooter={this._renderFooter}
          showsVerticalScrollIndicator={true}
          automaticallyAdjustContentInsets={false}
          contentContainerStyle={[this.props.contentContainerStyle]}/>
      </View>
    );
  },


  /**
   * 下拉刷新
   */
  _renderHeader() {
    var customHeader = this.props.customHeader;
    // 如果没有数据，显示暂无数据
    var isEmpty = this.state.isLoadTail && this._cache.length == 0;

    return (
      <View>
        {/*头部的loading效果*/}
        {this._renderRefreshIndicator()}

        {/*自定义头*/}
        {this.props.customHeader && this.props.customHeader()}

        {/*有自定义头部的空view显示在头部*/}
        {isEmpty && customHeader ? this._renderEmptyView() : null}
      </View>
    );
  },


  /**
   * 显示头部的进度指示条
   *
   * @returns {XML}
   * @private
   */
  _renderRefreshIndicator(){
    // 当前的刷新状态
    // pull 正在下拉，
    // push 正在上题
    var mode = this.state.isRefreshMode;

    if (mode === 'refresh') {
      return (
        <View style={styles.refresh}>
          <ActivityIndicatorIOS size='small'/>
          <Text style={styles.text}>正在加载...</Text>
        </View>
      );
    } else {
      return (
       <View style={styles.refresh}>
          {mode === 'push' ?
            <Image style={styles.arrow} source={require('img/arrow_up.png')} /> :
            <Image style={styles.arrow} source={require('img/arrow_down.png')} />
          }
          <Text style={styles.text}>{mode === 'push' ?  '松手更新' : '下拉刷新'}</Text>
      </View>
      );
    }
  },


  /**
   * 渲染ListView的footer
   */
  _renderFooter() {
    // 如果没有获取任何数据不显示footer
    if (this.state.isLoadTail || this._cache.length == 0) {
      return null;
    } else {
      return (
        <View style={styles.footer}>
          <ActivityIndicatorIOS size='small'/>
          <Text style={[styles.name,styles.text]}>正在加载</Text>
        </View>
      );
    }
  },


  /**
   * 获取url
   */
  _getURL() {
    var url = this.props.url;
    if (url.indexOf('?') != -1) {
      url += '&pageNum=' + this._page;
    } else {
      url += '?pageNum=' + this._page;
    }

    if (__DEV__) {
      console.log(url);
    }

    return url;
  },


  /**
   * 当释放当前responder
   */
  _handleResponderRelease(){
    if (__DEV__) {
      console.log('释放了当前的responder', this.state.isRefresh);
    }

    //快速的remove掉当前的提示，恢复ListView的位置
    if (this.state.isRefreshMode === 'pull') {
      if (this.offsetY > 0 && this.offsetY < OFFSET_Y) {
        this._listView.scrollResponderScrollTo(0, 50);
      }
    }
  },


  /**
   * 下拉滚动
   */
  _handleScroll(e) {
    //ListView向下的拉动距离
    this.offsetY = e.nativeEvent.contentInset.top + e.nativeEvent.contentOffset.y;
    if (__DEV__) {
      console.log('滚动的距离', this.offsetY);
    }

    //如果是下拉，
    //切换头部的状态，是下拉刷新，还是释放更新
    if (Math.abs(this.offsetY) <= OFFSET_Y) {
      this._changeHeaderMode(this.offsetY);
    }
  },


  /**
   * 切换头部的模式
   */
  _changeHeaderMode(dy){
    //下拉
    if (dy > 0 && dy < OFFSET_Y) {
      //如果当前的状态不是拉
      if (this.state.isRefreshMode != 'pull') {
        if (__DEV__) {
          console.log('切换为下拉状态');
        }
        this.setState({
          isRefreshMode: 'pull'
        });
      }
    } else {
      //如果offset大于设置的界限值，且为push状态
      if (this.state.isRefreshMode != 'push') {
        if (__DEV__) {
          console.log('切换状态为push状态');
        }
        this.setState({
          isRefreshMode: 'push'
        });
      }
    }
  },


  /**
   * 处理分页
   */
  _handlePagination() {
    //如果当前的状态正在获取更新，不去分页获取
    if (this.state.isRefresh) {
      return false;
    }

    //如果第一页的数量小与pagesize不再分页
    if (this._page == 0 && this._cache.length < this.props.pageSize) {
      return false;
    }

    this._page++;

    fetch(this._getURL())
      .then((res) => {
        this._cache = this._cache.concat(res.dataList);
        //最后一页
        if (res.dataList.length === 0) {
          this._page--;
        }

        this.setState({
          isRefresh: false,
          isLoadTail: res.dataList.length < this.props.pageSize
        });
        this.props.onDataReceive(res);
      });
  },


  _handleMomentumScrollEnd(e) {
    var offsetY = e.nativeEvent.contentInset.top + e.nativeEvent.contentOffset.y;
    if(__DEV__) {
      console.log('滚动的动画结束：offset:', offsetY);
    }


    if (offsetY == 0) {
      //如果当前的模式不是刷新模式,直接返回
      if (this.state.isRefreshMode != 'push') {
        return false;
      }

      //显示刷新
      this.setState({
        isRefreshMode: 'refresh'
      });

      //当前的页
      this._page = 0;
      //FIXED hack way
      this._listView._sentEndForContentLength = 0;

      //获取数据
      fetch(this._getURL())
        .then(
        onScrollFetchSuccess.bind(this),
        onScrollFetchFail.bind(this)
      );
    }

    //获取数据成功
    function onScrollFetchSuccess(res) {
      this._listView.scrollResponderScrollTo(0, 50);

      this._cache = res.dataList;
      this.setState({
        isRefreshMode: 'refresh', //不刷新
        isLoadTail: res.dataList.length < this.props.pageSize
      });

      this.props.onDataReceive(res);
    }

    //获取数据失败
    function onScrollFetchFail() {
      this._listView.scrollResponderScrollTo(0, 50);
      this.setState({
        isRefreshMode: 'refresh' //不刷新
      });
    }
  },


  /**
   * 初始化获取数据
   */
  _init() {
    InteractionManager.runAfterInteractions(async () => {
      this._page = 0;

      try {
        //获取数据
        var res = await fetch(this._getURL());
        this._cache = res.dataList;
        this.setState({
          isLoadTail: res.dataList.length < PAGE_SIZE
        });
        this.props.onDataReceive(res);
      } catch (e) {
        this._cache = [];
        this.setState({
          isLoadTail: true
        });
      } finally {
        this._listView.scrollResponderScrollTo(0, 50);
      }
    });
  },

  /**
   * 刷新指定列表
   */
  refreshListView(){
    this._init();
  }
});


var styles = StyleSheet.create({
  container: {
    flex: 1
  },
  loading: {
    flex: 1,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center'
  },
  refresh: {
    width: SCREEN_WIDTH,
    height: LOADING_HEIGHT,
    borderBottomWidth: 1 / PixelRatio.get(),
    borderColor: '#ebebeb',
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  noDataContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  },
  footer: {
    width: SCREEN_WIDTH,
    height: 30,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
    borderBottomWidth: 1 / PixelRatio.get(),
    borderColor: '#e1e1e1'
  },
  txt: {
    fontSize: 14,
    color: '#cfd5dd'
  },
  text: {
    fontSize: 14,
    color: '#939495',
  },
  face: {
    width: 93,
    height: 93,
    marginBottom: 15
  },
  foot: {
    alignSelf: 'stretch',
    justifyContent: 'flex-end',
    paddingLeft: 10,
    paddingRight: 10,
    paddingBottom: 10
  },
  button: {
    backgroundColor: '#43c6a6',
    alignSelf: 'stretch',
    alignItems: 'center',
    paddingTop: 13,
    paddingBottom: 13
  },
  cont: {
    fontSize: 16,
    color: '#FFF'
  },
  arrow: {
    width: 20,
    height: 20,
  },
});


module.exports = PullRefreshListView;
